#pragma once
#include "Runtime/CGI/CGICommandList.h"
#include "RenderGraphPass.h"
#include "RenderGraphPrefix.h"
#include "Runtime/Thread/Pipe.h"
#include "Runtime/Thread/Task.h"

namespace Alice{
    class FRDGScopeState
    {
    public:
        CGICommandListImmediate*mCGICommandList;
        FRDGScopeState(CGICommandListImmediate*inCGICommandList):mCGICommandList(inCGICommandList){}
    };
    class RDGBuilder:public FRDGScopeState
    {
    public:
        struct ParallelSetupTasks
        {
            std::vector<TaskHandle*> mTasks[ERDGSetupTaskWaitPoint::MAX];
            bool mbEnabled=false;
        };
        ParallelSetupTasks mParallelSetupTasks;
        CGICommandListScopedExtendResourceLifetime mExtendResourceLifetimeScope;
        std::vector<RDGDispatchPass*> mDispatchPasses;
        RDGBuilder(CGICommandListImmediate& RHICmdList);
        /** Adds a pass that takes a FRDGDispatchPassBuilder instead of a RHI command list. The lambda should create command lists
         *  and launch tasks to record commands into them. Each task should call EndRenderPass() (if raster) and FinishRecording()
         *  to complete each command list. The user is responsible for task management of dispatched command lists.
         */
        template <typename ParameterStructType, typename LaunchLambdaType>
        RDGPass* AddDispatchPass(const ParameterStructType* ParameterStruct, ERDGPassFlags Flags, LaunchLambdaType&& LaunchLambda)
        {
            using DispatchPassType = TRDGDispatchPass<ParameterStructType, LaunchLambdaType>;
            RDGDispatchPass*pass=new DispatchPassType(ParameterStruct,Flags,std::forward<LaunchLambdaType&&>(LaunchLambda));
            mDispatchPasses.push_back(pass);
            return pass;
        }
        void SetupDispatchPassExecute();
        
        /** Launches a task that is synced prior to graph execution. If parallel execution is not enabled, the lambda is run immediately. */
        template <typename TaskLambda>
        TaskHandle* AddCommandListSetupTask(TaskLambda&& inTask, bool bCondition = true, ERDGSetupTaskWaitPoint inWaitPoint = ERDGSetupTaskWaitPoint::Compile)
        {
            return AddCommandListSetupTask(std::forward<TaskLambda>(inTask), nullptr, std::vector<TaskHandle*>{}, ETaskPriority::Normal, bCondition, inWaitPoint);
        }
        template <typename TaskLambda, typename PrerequisitesCollectionType>
        TaskHandle* AddCommandListSetupTask(TaskLambda&& Task, PrerequisitesCollectionType&& Prerequisites, ETaskPriority Priority = ETaskPriority::Normal, bool bCondition = true, ERDGSetupTaskWaitPoint WaitPoint = ERDGSetupTaskWaitPoint::Compile)
        {
            return nullptr;
        }
        template <typename TaskLambda, typename PrerequisitesCollectionType>
        TaskHandle* AddCommandListSetupTask(TaskLambda&& inTask, Pipe* Pipe, PrerequisitesCollectionType&& inPrerequisites, ETaskPriority inPriority = ETaskPriority::Normal, bool bCondition = true, ERDGSetupTaskWaitPoint WaitPoint = ERDGSetupTaskWaitPoint::Compile)
        {
            TaskHandle*task=Tasks::Launch(TEXT("AddCommandListSetupTask"),std::forward<TaskLambda>(inTask),
                std::forward<PrerequisitesCollectionType>(inPrerequisites),
                inPriority,EExtendedTaskPriority::None);
            return task;
        }
        void Execute();
    };
}
